package com.xy.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.tencentcloudapi.iai.v20200303.models.Candidate;
import com.tencentcloudapi.iai.v20200303.models.Result;
import com.tencentcloudapi.iai.v20200303.models.SearchPersonsResponse;
import com.xy.config.AipFaceClient;
import com.xy.constants.ControlCharacter;
import com.xy.constants.RedisConstant;
import com.xy.entity.*;
import com.xy.eum.EumInspect;
import com.xy.request.BaseRequest;
import com.xy.request.ExhibitionRequest;
import com.xy.request.FaceDetectionRequest;
import com.xy.request.GeneralRecordRequest;
import com.xy.response.InspectResponse;
import com.xy.response.ViewerResponse;
import com.xy.service.*;
import com.xy.tx.TxCommon;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.*;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 鉴权认证实现类
 *
 * @author guojian
 */
@Service
@AllArgsConstructor
@Slf4j
public class IInspectServiceImpl implements IInspectService {
	private final IViewerService viewerService;
	private final IPositionGroupViewerTypeService positionGroupViewerTypeService;
	private final IViewerSortService viewerSortService;
	private final IGeneralRecordService generalRecordService;
	private final IRuleService ruleService;
	private final BladeRedis bladeRedis;
	private final IExhibitionService exhibitionService;
	private final ITimeStageService timeStageService;
	private final IAbnormalRecordService abnormalRecordService;

	/**
	 * 查询用户
	 *
	 * @param t
	 * @param longIds
	 * @return
	 */
	@Override
	public List<ViewerEntity> viewerList(ViewerEntity t, List<Long> longIds) {
		List<ExhibitionEntity> exhibitionEntityList = exhibitionService.listByIds(longIds);
		List<ExhibitionEntity> entityList = exhibitionEntityList.stream().filter(o -> o.getCloseStatus().equals(0)).collect(Collectors.toList());
		if(Func.isEmpty(entityList)){
			throw new ServiceException("展会不存在、或已关闭");
		}

		LambdaQueryWrapper<ViewerEntity> queryWrapper = Wrappers.<ViewerEntity>query().lambda().eq(Func.isNotEmpty(t.getIdCard()), ViewerEntity::getIdCard, t.getIdCard())
			.eq(Func.isNotEmpty(t.getTwoCode()), ViewerEntity::getTwoCode, t.getTwoCode())
			.eq(Func.isNotEmpty(t.getSwipeCard()), ViewerEntity::getSwipeCard, t.getSwipeCard())
			.in(ViewerEntity::getExhibitionId, longIds);
		List<ViewerEntity> viewerEntityList = viewerService.list(queryWrapper);

		if (CollectionUtil.isEmpty(viewerEntityList)) {
			throw new ServiceException("不允许未注册证件入场");
		}
		return viewerEntityList;
	}

	/**
	 * 核验
	 *
	 * @param baseRequest
	 * @param oauthType
	 * @return
	 */
	@Override
	public InspectResponse oauthInspect(ViewerEntity t, BaseRequest baseRequest, String oauthType) {
		List<ExhibitionRequest> exhibitionList = baseRequest.getExhibitionList();
		List<Long> exhibitionIds = exhibitionList.stream().map(ExhibitionRequest::getExhibitionId).collect(Collectors.toList());
		List<ViewerEntity> viewerList = viewerList(t, exhibitionIds);
		//位置与类型
		List<PositionGroupViewerTypeEntity> pointGroupTicketTypeEntityList = positionGroupViewerTypeService.list(Wrappers.<PositionGroupViewerTypeEntity>query().lambda().eq(PositionGroupViewerTypeEntity::getPositionGroupId, baseRequest.getPositionGroupId())
			.in(PositionGroupViewerTypeEntity::getExhibitionId, exhibitionIds));
		Map<Long, List<PositionGroupViewerTypeEntity>> listMap = pointGroupTicketTypeEntityList.stream().collect(Collectors.groupingBy(PositionGroupViewerTypeEntity::getExhibitionId));
		//判断票证类型入场次数
		InspectResponse inspectResponse = BeanUtil.newInstance(InspectResponse.class);
		List<ViewerResponse> viewerResponseList = new ArrayList<>();
		inspectResponse.setSpecial(1);
		inspectResponse.setWhetherOrNot(ControlCharacter.WHETHER_OR_NO);
		inspectResponse.setFaceRegister(1L);
//		Map<Long, TerExhibitionVO> map = exhibitionVOList.stream().collect(Collectors.toMap(TerExhibitionVO::getExhibitionId, o -> o));
		RuleEntity ruleEntity = ruleService.getById(baseRequest.getRuleId());
		viewerList.forEach(o -> {
			//实例化
			ViewerResponse viewerResponse = BeanUtil.newInstance(ViewerResponse.class);
			viewerResponse.setWhetherOrNot(ControlCharacter.WHETHER_OR_YES);
			if (Func.isEmpty(o.getHeadUrl()) && ruleEntity.getFaceRegisterStatus().equals(ControlCharacter.FACE_REGISTER_YES)) {
				inspectResponse.setFaceRegister(ControlCharacter.FACE_REGISTER_YES);
				inspectResponse.setRecordface(o.getIdCard());
				if(oauthType.equals(ControlCharacter.OAUTH_TYPE_CARD_NO)){
					inspectResponse.setRecordface(o.getTwoCode());
				}

			}
			ExhibitionEntity exhibition = exhibitionService.getById(o.getExhibitionId());
			//证件类型
			ViewerSortEntity viewerSort = viewerSortService.getById(o.getViewerTypeId());

			//数据组装
			ticketData(o, exhibition, viewerResponse, viewerSort);
			// 黑名单 公安、场馆
			String keyExhibition = RedisConstant.LIMITED_ACCESS.concat(o.getExhibitionId().toString()).concat(o.getIdCard());
			BlacklistEntity o1 = bladeRedis.get(keyExhibition);
			if (o1 != null) {
				messageData(viewerResponseList, viewerResponse, EumInspect.LIMITED_ACCESS);
				return;
			}
			//票证状态
			if (ControlCharacter.VIEWER_STATUS_NO.equals(o.getViewerStatus())) {
				messageData(viewerResponseList, viewerResponse, EumInspect.TICKET_DISABLED);
				return;
			}
			//特殊分类
			if (viewerSort.getSpecial().equals(0)) {
				inspectResponse.setSpecial(viewerSort.getSpecial());
				viewerResponseList.add(viewerResponse);
				return;
			}
			//二维码票证人脸不存在
			if (oauthType.equals(ControlCharacter.OAUTH_TYPE_CARD_NO) && ruleEntity.getFaceRegisterStatus().equals(ControlCharacter.FACE_REGISTER_NO)) {
				if (ruleEntity.getFaceCompareStatus().equals(0) && StringUtil.isBlank(o.getHeadUrl())) {
					messageData(viewerResponseList, viewerResponse, EumInspect.TICKET_FACE_IS_NOT_REGISTERED);
					return;
				}
			}
			//票证分类
			if (listMap.containsKey(o.getExhibitionId())) {
				List<PositionGroupViewerTypeEntity> ticketTypeEntityList = listMap.get(o.getExhibitionId());
				boolean anyMatch = ticketTypeEntityList.stream().anyMatch(s -> s.getViewerTypeId().equals(o.getViewerTypeId()) && s.getFrontBack().equals(ControlCharacter.JUST_STAUTS_));
				boolean anyMatch1 = ticketTypeEntityList.stream().anyMatch(s -> !s.getViewerTypeId().equals(o.getViewerTypeId()) && s.getFrontBack().equals(ControlCharacter.BACK_STAUTS));
				if (!anyMatch && !anyMatch1) {
					messageData(viewerResponseList, viewerResponse, EumInspect.ENTRANCE_GUARD_NOT_ALLOW_TICKET);
					return;
				}
			}
			//次数
			List<GeneralRecordEntity> recordEntityList = generalRecordService.list(Wrappers.<GeneralRecordEntity>query().lambda().eq(GeneralRecordEntity::getViewerId, o.getId())
				.orderByDesc(GeneralRecordEntity::getPassTime));
//			List<TerRecordVO> recordVOList = BeanUtil.copy(list, TerRecordVO.class);
//			if (CollectionUtil.isNotEmpty(recordEntityList) && recordEntityList.size() > 5) {
//				oauthTicketVO.setRecordList(recordVOList.subList(0, 5));
//			} else {
//				oauthTicketVO.setRecordList(recordVOList);
//			}
			//当日
			long count = recordEntityList.stream().filter(r -> DateUtil.formatDate(r.getPassTime()).equals(DateUtil.formatDate(new Date()))).count();
			viewerResponse.setOperateNum(Func.toStr(count));
			if (ControlCharacter.UNRESTRICTED_NUM != viewerSort.getEverydayNumber() && count >= viewerSort.getEverydayNumber()) {
				messageData(viewerResponseList, viewerResponse, EumInspect.DAY_ADMISSION_TIMES_UPPER);
				return;
			}
			//总次数
			if (ControlCharacter.UNRESTRICTED_NUM != viewerSort.getTotalNumber() && recordEntityList.size() >= viewerSort.getTotalNumber()) {
				messageData(viewerResponseList, viewerResponse, EumInspect.ADMISSION_TIMES_UPPER);
				return;
			}
			//时间段 人证 票证
			List<TimeStageEntity> timeEntityList = timeStageService.queryTimeStageEntity(viewerSort.getId());
			List<TimeStageEntity> userList = timeStageService.queryTimeStageEntity(o.getId());
			if (CollectionUtil.isNotEmpty(userList)) {
				boolean allMatch = userList.stream().anyMatch(s -> {
					//是否提前入场
					if (DateUtil.belongCalendar(new Date(), DateUtil.minusDays(s.getStartTime(), viewerSort.getAheadDay()), s.getEndTime())) {
						return true;
					}
					return false;
				});
				if (!allMatch) {
					messageData(viewerResponseList, viewerResponse, EumInspect.TIME_NOT_ALLOW_TICKET);
					return;
				}
			}
			if (CollectionUtil.isEmpty(userList) && CollectionUtil.isNotEmpty(timeEntityList)) {
				boolean allMatch = timeEntityList.stream().anyMatch(s -> DateUtil.belongCalendar(new Date(), s.getStartTime(), s.getEndTime()));
				if (!allMatch) {
					messageData(viewerResponseList, viewerResponse, EumInspect.TIME_NOT_ALLOW_TICKET);
					return;
				}
			}
			viewerResponseList.add(viewerResponse);
		});
		return returnData(viewerResponseList, inspectResponse);

	}

	/**
	 * 人脸核验
	 *
	 * @param faceDetectionRequest
	 * @return
	 */
	@Override
	@SneakyThrows
	public ViewerEntity face(FaceDetectionRequest faceDetectionRequest) {
		List<String> collect = faceDetectionRequest.getExhibitionList().stream().map(o -> Func.toStr(o.getExhibitionId())).collect(Collectors.toList());
		Long search = null;
		RuleEntity ruleEntity = ruleService.getById(faceDetectionRequest.getRuleId());
		if (ControlCharacter.DISCERN_CHANNEL_TX.equals(ruleEntity.getIdentificationChannel())) {
			String[] objects = collect.stream().toArray(String[]::new);
			SearchPersonsResponse searchPersonsResponse = TxCommon.searchPersons(faceDetectionRequest.getFaceDetectionUrl(), objects, Float.valueOf(ruleEntity.getFaceThreshold()));
			if (searchPersonsResponse == null) {
				throw new ServiceException("不允许未注册身份信息入场!!");
			}
			Result result = searchPersonsResponse.getResults()[0];
			if (null == result.getCandidates() || result.getCandidates().length <= 0) {
				throw new ServiceException("不允许未注册身份信息入场");
			}
			Candidate candidate = result.getCandidates()[0];
			search = Long.parseLong(candidate.getPersonId());
		} else {
			search = AipFaceClient.faceSearch(ruleEntity.getFaceThreshold(), faceDetectionRequest.getFaceDetectionUrl(), collect);
		}
		if (search == null) {
			throw new ServiceException("不允许未注册身份信息入场");
		}
		ViewerEntity viewerEntity = viewerService.getById(search);
		if (viewerEntity == null) {
			throw new ServiceException("不允许未注册身份信息入场");
		}
		viewerEntity.setSwipeCard(null);
		viewerEntity.setTwoCode(null);
		return viewerEntity;
	}

	@Override
	public Boolean facefFaceRegister(FaceDetectionRequest faceDetectionRequest) {
		RuleEntity ruleEntity = ruleService.getById(faceDetectionRequest.getRuleId());
		if (ControlCharacter.RECOGNIZE_FACE_YES.equals(ruleEntity.getFaceRecognizeStatus())) {
			//推送至消息队列
//			QueueFaceDTO queueFaceDTO = BeanUtil.newInstance(QueueFaceDTO.class);
//			queueFaceDTO.setGroupId(ticketEntity.getExhibitionId().toString());
//			queueFaceDTO.setTicketId(ticketEntity.getId().toString());
//			queueFaceDTO.setPhotoUrl(registerDTO.getFaceUrl());
//			//百度人脸注册
//			rabbitTemplate.convertAndSend(RabbitConstant.TOPIC_ADD_FACE_EXCHANGE,RabbitConstant.TOPIC_ADD_FACE_ROUTING_KEY_ONE,queueFaceDTO);
		}
		LambdaUpdateWrapper<ViewerEntity> updateWrapper = Wrappers.<ViewerEntity>update().lambda();
		updateWrapper.set(ViewerEntity::getHeadUrl, faceDetectionRequest.getFaceDetectionUrl());
		if(Func.isNotEmpty(faceDetectionRequest.getRecordface()) && faceDetectionRequest.getRecordface().length()>17){
			updateWrapper.eq(ViewerEntity::getIdCard, faceDetectionRequest.getRecordface());
		}else{
			updateWrapper.eq(ViewerEntity::getTwoCode, faceDetectionRequest.getRecordface());
		}
		return viewerService.update(updateWrapper);
	}

	@Override
	public Boolean recordSave(GeneralRecordRequest generalRecordRequest) {
		//判断数据类型
		if (ControlCharacter.RECORD_TYPE_OFF_LINE.equals(generalRecordRequest.getGeneralType())) {
			//离线数据进入消息队列进行分析存储
//			rabbitTemplate.convertAndSend(RabbitConstant.TOPIC_RECORD_OFF_LINE_EXCHANGE,RabbitConstant.TOPIC_RECORD_OFF_LINE_ROUTING_KEY_ONE,recordDTO);
			return true;
		}
		if (Func.isEmpty(generalRecordRequest.getOauthKey())) {
			log.info("鉴权key为空、提交的门禁记录参数为：{}", generalRecordRequest);
			throw new ServiceException("鉴权key为空");
		}
		List<ViewerResponse> viewerResponseList = bladeRedis.get(RedisConstant.OAUTH_KEY.concat(generalRecordRequest.getOauthKey()));
		if (Func.isEmpty(viewerResponseList)) {
			log.info("门禁记录重复提交：提交的key：{}", generalRecordRequest.getOauthKey());
			return true;
		}
		bladeRedis.del(RedisConstant.OAUTH_KEY.concat(generalRecordRequest.getOauthKey()));
		List<ViewerResponse> responseList = viewerResponseList.stream().filter(o -> o.getWhetherOrNot().equals(ControlCharacter.WHETHER_OR_YES)).collect(Collectors.toList());
		if (Func.isNotEmpty(responseList)) {
			//正常门禁集合
			List<GeneralRecordEntity> recordEntityList = new ArrayList<>();
			responseList.forEach(o -> {
				GeneralRecordEntity generalRecordEntity = BeanUtil.copy(generalRecordRequest, GeneralRecordEntity.class);
				//数据组装
				generalRecordEntity.setGeneralProof(generalRecordRequest.getRecordViewer());
				dataRecordList(generalRecordEntity, o);
				if (o.getWhetherOrNot().equals(ControlCharacter.WHETHER_OR_YES)) {
					//本地存储
					recordEntityList.add(generalRecordEntity);
				}
			});
			return generalRecordService.saveBatch(recordEntityList);
		}
		//非正常门禁集合
		List<AbnormalRecordEntity> abnormalRecordEntityList = new ArrayList<>();
		viewerResponseList.forEach(o -> {
			dataIllegaList(abnormalRecordEntityList, generalRecordRequest, o);

		});
		if (CollectionUtil.isNotEmpty(abnormalRecordEntityList)) {
			abnormalRecordService.saveBatch(abnormalRecordEntityList);
		}
		return  true;

	}

	@Override
	public Boolean abnormalRecordSave(GeneralRecordRequest generalRecordRequest) {
		List<ViewerResponse> ticketDTOList = bladeRedis.get(RedisConstant.OAUTH_KEY.concat(generalRecordRequest.getOauthKey()));
		if (CollectionUtil.isEmpty(ticketDTOList)) {
			log.info("非法保存门禁记录重复提交：提交的key：{}", generalRecordRequest.getOauthKey());
			return true;
		}
		//非正常门禁集合
		List<AbnormalRecordEntity> abnormalRecordEntityList = new ArrayList<>();
		ticketDTOList.forEach(o -> {
			dataIllegaList(abnormalRecordEntityList, generalRecordRequest, o);
		});
		bladeRedis.del(RedisConstant.OAUTH_KEY.concat(generalRecordRequest.getOauthKey()));
		return abnormalRecordService.saveBatch(abnormalRecordEntityList);
	}

	/**
	 * 非法数据组装
	 *
	 * @param o
	 */
	public void dataIllegaList(List<AbnormalRecordEntity> abnormalRecordEntityList, GeneralRecordRequest generalRecordRequest, ViewerResponse o) {
		AbnormalRecordEntity abnormalRecord = BeanUtil.copy(generalRecordRequest, AbnormalRecordEntity.class);
		abnormalRecord.setIllicitViewer(generalRecordRequest.getRecordViewer());
		abnormalRecord.setExhibitionId(o.getExhibitionId());
		abnormalRecord.setExhibitionName(o.getExhibitionName());
		abnormalRecord.setAbnormalContent(o.getMessage());
		abnormalRecord.setAbnormalType(o.getErrorType() + "");
		abnormalRecordEntityList.add(abnormalRecord);
	}

	/**
	 * 正常数据组装
	 *
	 * @param
	 * @param o
	 */
	public void dataRecordList(GeneralRecordEntity generalRecordEntity, ViewerResponse o) {
		generalRecordEntity.setExhibitionId(o.getExhibitionId());
		generalRecordEntity.setExhibitionName(o.getExhibitionName());
		generalRecordEntity.setViewerId(o.getViewerId());
		generalRecordEntity.setViewerName(o.getViewerName());
		generalRecordEntity.setViewerTypeId(o.getViewerTypeId());
		generalRecordEntity.setViewerTypeName(o.getViewerTypeName());
	}

	/**
	 * 用户信息
	 *
	 * @param o
	 * @param
	 */
	public void 	ticketData(ViewerEntity o, ExhibitionEntity exhibition, ViewerResponse inspectResponse, ViewerSortEntity viewerSort) {
		//实例化
		inspectResponse.setViewerId(o.getId());
		inspectResponse.setWhetherOrNot(ControlCharacter.WHETHER_OR_YES);
		//用户信息
		inspectResponse.setViewerName(o.getName());
		inspectResponse.setHeadUrl(o.getHeadUrl());
		//用户所属展会
		inspectResponse.setExhibitionName(exhibition.getExhibitionName());
		inspectResponse.setExhibitionId(exhibition.getId());
		//分类信息
		inspectResponse.setViewerTypeName(viewerSort.getSortName());
		inspectResponse.setViewerTypeId(viewerSort.getId());
		inspectResponse.setTotalNum(Func.toStr(viewerSort.getEverydayNumber()));

	}

	/**
	 * 消息组装
	 */
	public void messageData(List<ViewerResponse> viewerResponseList, ViewerResponse viewerResponse, EumInspect eumInspect) {
		viewerResponse.setWhetherOrNot(ControlCharacter.WHETHER_OR_NO);
		viewerResponse.setMessage(eumInspect.getInfo());
		viewerResponse.setErrorType(eumInspect.getCode());

		viewerResponseList.add(viewerResponse);
	}

	/**
	 * 返回信息
	 *
	 * @return
	 */
	public InspectResponse returnData(List<ViewerResponse> viewerResponseList, InspectResponse inspectResponse) {
		List<ViewerResponse> responseList = viewerResponseList.stream().filter(o -> o.getWhetherOrNot().equals(ControlCharacter.WHETHER_OR_YES)).collect(Collectors.toList());
		//缓存Key
		String key = StringUtil.randomUUID();

		inspectResponse.setOauthKey(key);
		if (CollectionUtil.isNotEmpty(responseList)) {
			ViewerResponse viewerResponse = responseList.stream().findFirst().get();
			inspectResponse.setWhetherOrNot(ControlCharacter.WHETHER_OR_YES);
			inspectResponse.setHeadUrl(viewerResponse.getHeadUrl());
			inspectResponse.setViewerTypeName(viewerResponse.getViewerTypeName());
			inspectResponse.setName(viewerResponse.getViewerName());
			inspectResponse.setOperateNum(viewerResponse.getOperateNum());
			inspectResponse.setTotalNum(viewerResponse.getTotalNum());
			bladeRedis.set(RedisConstant.OAUTH_KEY.concat(key), responseList);
			return inspectResponse;
		}
		bladeRedis.set(RedisConstant.OAUTH_KEY.concat(key), viewerResponseList);
		ViewerResponse viewerResponse = viewerResponseList.get(0);
		inspectResponse.setMessage(viewerResponse.getMessage());
		inspectResponse.setErrorType(viewerResponse.getErrorType());
		inspectResponse.setViewerTypeName(viewerResponse.getViewerTypeName());
		inspectResponse.setName(viewerResponse.getViewerName());
		inspectResponse.setOperateNum(viewerResponse.getOperateNum());
		inspectResponse.setTotalNum(viewerResponse.getTotalNum());
		return inspectResponse;
	}


}
